#include "clientSession.h"
#include "../log/log.h"
#include "../server_tlv/tlv.h"
// 函数流程
// cdFunc--->change--->handle

// 核心函数——根据栈重新构建真实目录以及虚拟目录
int rebuildPathsFromStack(clientSession_t *pClientSession)
{
    // printf("rebuildPathsFromStack\n");
    //  清空现有路径
    strcpy(pClientSession->truePath, g_root_path);
    strcpy(pClientSession->virtualPath, "/");
    tlv_msg_t msg;

    if (pClientSession->folderStack.stackSize <= 1)
    {
        // printf("目前所在真实目录：%s\n", pClientSession->truePath);
        // printf("目前所在虚拟目录：%s\n", pClientSession->virtualPath);
        bzero(&msg, sizeof(msg));
        tlv_create(&msg, CMD_RESPONSE, strlen(pClientSession->virtualPath), pClientSession->virtualPath);
        tlv_send(pClientSession->netfd, &msg);
        // printf("传回去的虚拟路径%s\n", pClientSession->virtualPath);
        return 0; // 如果栈为空，保持为根路径
    }

    // 从栈顶开始遍历路径栈，重建路径
    // 需要反向遍历，设置一个数组存储路径
    int size = pClientSession->folderStack.stackSize;
    char *paths[256] = {0}; // 指针数组存储路径
    Node_t *current = pClientSession->folderStack.pTop;
    int index = 0;
    while (current != NULL)
    {
        paths[index++] = current->path;
        current = current->pNext; // 向下遍历
    }
    // 反向拼接路径
    for (int i = size - 1; i >= 0; i--)
    {
        if (strcmp(paths[i], "/") == 0)
            continue; // 跳过栈底的"/"
        // 处理真实路径
        if (strcmp(pClientSession->truePath, g_root_path) != 0)
        {
            strcat(pClientSession->truePath, "/");
        }
        strcat(pClientSession->truePath, paths[i]);
        // 处理虚拟路径
        if (strcmp(pClientSession->virtualPath, "/") != 0)
        {
            strcat(pClientSession->virtualPath, "/");
        }
        strcat(pClientSession->virtualPath, paths[i]);
    }

    // printf("目前所在真实目录：%s\n", pClientSession->truePath);
    // printf("目前所在虚拟目录：%s\n", pClientSession->virtualPath);
    bzero(&msg, sizeof(msg));
    tlv_create(&msg, CMD_RESPONSE, strlen(pClientSession->virtualPath), pClientSession->virtualPath);
    tlv_send(pClientSession->netfd, &msg);
    printf("传回去的虚拟路径%s\n", pClientSession->virtualPath);
    return 0;
}
// 选择绝对路径or相对路径
int changeDirectory(clientSession_t *pClientSession, char *path)
{
    // printf("changeDirectory,path = %s\n",path);
    if (path[0] == '/') // 处理绝对路径
    {
        handleAbsolutePath(pClientSession, path);
    }
    else // 处理相对路径
    {
        handleRelativePath(pClientSession, path);
    }
    return 0;
}
// 处理绝对路径
int handleAbsolutePath(clientSession_t *pClientSession, const char *path)
{
    // printf("handle success,path = %s\n",path);
    // 清空当前栈
    folderStackDestroy(&pClientSession->folderStack);
    push(&pClientSession->folderStack, "/");
    strncpy(pClientSession->truePath, g_root_path, sizeof(pClientSession->truePath) - 1);
    pClientSession->truePath[sizeof(pClientSession->truePath) - 1] = '\0';
    strncpy(pClientSession->virtualPath, "/", sizeof(pClientSession->virtualPath) - 1);
    pClientSession->virtualPath[sizeof(pClientSession->virtualPath) - 1] = '\0';

    char temp[1024] = {0};
    strcpy(temp, path);
    char checkPath[1024] = {0};
    strcpy(checkPath, pClientSession->truePath);
    tlv_msg_t msg;
    char value[1024] = {0};

    char *component = strtok(temp + 1, "/"); // 从第一个/之后查找/
    while (component != NULL)
    {
        if (strcmp(component, ".") == 0)
        {
            // 还是在当前目录
        }
        else if (strcmp(component, "..") == 0)
        {
            // 只有不在根目录时才回退
            if (pClientSession->folderStack.stackSize > 1)
            {
                pop(&pClientSession->folderStack);
            }
        }
        else // to do if检查目录是否合理
        {

            int lens = strlen(checkPath);
            if (checkPath[lens - 1] != '/')
            {
                strcat(checkPath, "/");
            }
            // strcat(checkPath,"/");
            strcat(checkPath, component);
            // printf("checkpath = %s\n", checkPath);
            if (access(checkPath, F_OK) == 0)
            {
                push(&pClientSession->folderStack, component);
            }
            else
            {
                // printf("cd 错误\n");
                // printf("目前所在目录为:%s\n",pClientSession->truePath);
                bzero(&msg, sizeof(msg));
                strcpy(value, "输入的路径有误");
                tlv_create(&msg, CMD_RESPONSE, strlen(value), value);
                tlv_send(pClientSession->netfd, &msg);
                return 0;
            }
        }
        component = strtok(NULL, "/"); // 继续向后查找
    }
    rebuildPathsFromStack(pClientSession);
    return 0;
}
// 处理相对路径 to do
int handleRelativePath(clientSession_t *pClientSession, const char *path)
{
    if (pClientSession->folderStack.stackSize <= 1)
    {
        push(&pClientSession->folderStack, "/");
    }
    folderStack_t originStack;
    folderStackInit(&originStack);

    // 记录原本栈信息
    Node_t *curNode = pClientSession->folderStack.pTop;
    while (curNode != NULL)
    {
        push(&originStack, curNode->path);
        curNode = curNode->pNext;
    }

    char temp[1024] = {0};
    strcpy(temp, path);

    char *component = strtok(temp, "/");
    printf("%s\n", component);
    while (component != NULL)
    {
        if (strcmp(component, ".") == 0)
        {
            // 还是当前目录
        }
        else if (strcmp(component, "..") == 0)
        {
            if (pClientSession->folderStack.stackSize > 1)
            {
                pop(&pClientSession->folderStack);
            }
        }
        else
        {
            push(&pClientSession->folderStack, component);
        }
        component = strtok(NULL, "/");
    }
    rebuildPathsFromStack(pClientSession);
    return 0;
}

// 使用栈来实现cd命令
int cdFunc(clientSession_t *pClientSession, char *buf)
{
    LOG_INFO("cd start");
    tlv_msg_t msg;
    bzero(&msg, sizeof(msg));
    char value[1024] = {0};

    if (strcmp(buf, "/") == 0 || strcmp(buf, " ") == 0) // 判断用户输入为cd / 或者cd
    {
        folderStackDestroy(&pClientSession->folderStack); // 清空栈
        push(&pClientSession->folderStack, "/");          // 将根目录压栈
        rebuildPathsFromStack(pClientSession);            // 基于栈重新构建真实以及虚拟路径
    }
    else if (strcmp(buf, "..") == 0) // 判断用户输入为cd ..
    {
        if (pClientSession->folderStack.stackSize <= 1)
        {
            strcpy(value, "目前已在根目录");
            tlv_create(&msg, CMD_RESPONSE, strlen(value), value);
            tlv_send(pClientSession->netfd, &msg);
            printf("stack size = %d\n",pClientSession->folderStack.stackSize);
            return 0; // 如果已经在根目录保持不变
        }
        else
        {
            pop(&pClientSession->folderStack); // 将栈顶弹栈
            rebuildPathsFromStack(pClientSession);
        }
    }
    else if (strcmp(buf, ".") == 0)
    {
        return 0;
    }
    else
    {
        return changeDirectory(pClientSession, buf);
    }

    return 0;
}

int mkdirFunc(clientSession_t *pClientSession, char *buf)
{
    // printf("mkdir success\n");
    // printf("当前真实目录为:%s\n", pClientSession->truePath);
    tlv_msg_t msg;
    bzero(&msg, sizeof(msg));
    char value[1024] = {0};
    char dest[1024] = {0};
    strcpy(dest, pClientSession->truePath);
    int lens = strlen(dest);
    printf("lens = %d\n", lens);
    if (dest[lens - 1] != '/')
    {
        strcat(dest, "/");
    }
    strcat(dest, buf);
    printf("dest = %s\n", dest);
    if (access(dest, F_OK) == 0)
    {
        // printf("文件夹已存在\n");
        strcpy(value, "创建文件夹失败，当前文件夹已存在");
        tlv_create(&msg, CMD_RESPONSE, strlen(value), value);
        tlv_send(pClientSession->netfd, &msg);
        printf("%s\n", msg.value); // 服务端测试
        return 0;
    }
    strcpy(value, "创建文件夹成功");
    tlv_create(&msg, CMD_RESPONSE, strlen(value), value);
    tlv_send(pClientSession->netfd, &msg);
    printf("%s\n", msg.value);
    mode_t old_mask = umask(0); // 获取并临时设置为0
    umask(old_mask);            // 恢复原值
    mkdir(dest, 0777);

    // ERROR_CHECK(ret, -1, "mkdir error");

    return 0;
}

int rmdirFunc(clientSession_t *pClientSession, char *buf)
{
    // printf("rmdir success\n");
    tlv_msg_t msg;
    bzero(&msg, sizeof(msg));
    char value[1024] = {0};
    char dest[1024] = {0};
    strcpy(dest, pClientSession->truePath);
    int lens = strlen(dest);
    if (dest[lens - 1] != '/')
    {
        strcat(dest, "/");
    }
    strcat(dest, buf);
    // printf("dest = %s\n", dest);
    if (access(dest, F_OK) == 0)
    {
        strcpy(value, "删除文件夹成功");
        tlv_create(&msg, CMD_RESPONSE, strlen(value), value);
        tlv_send(pClientSession->netfd, &msg);
        printf("%s\n", msg.value); // 服务端测试
        rmdir(dest);
        return 0;
    }
    strcpy(value, "删除文件夹失败，文件夹不存在");
    tlv_create(&msg, CMD_RESPONSE, strlen(value), value);
    tlv_send(pClientSession->netfd, &msg);
    printf("%s\n", msg.value); // 服务端测试
    return 0;
}

int pwdFunc(clientSession_t *pClientSession)
{
    tlv_msg_t msg;
    bzero(&msg, sizeof(msg));
    tlv_create(&msg, CMD_RESPONSE, strlen(pClientSession->virtualPath), pClientSession->virtualPath);
    tlv_send(pClientSession->netfd, &msg);
    printf("pwd %s\n", msg.value);
    return 0;
}

int lsFunc(clientSession_t *pClientSession)
{
    tlv_msg_t msg;
    char value[4096] = {0};
    strcpy(value,"有以下文件：");
    // printf("ls truepath = %s\n", pClientSession->truePath);
    DIR *dir = opendir(pClientSession->truePath);

    struct dirent *dirent;

    while ((dirent = readdir(dir)) != NULL)
    {
        if ((strcmp(dirent->d_name, ".") != 0) && (strcmp(dirent->d_name, "..") != 0))
        {
            strcat(value, dirent->d_name);
            strcat(value, " ");
        }
        // printf("%s \n", dirent->d_name);
    }
    bzero(&msg, sizeof(msg));
    tlv_create(&msg, CMD_RESPONSE, strlen(value), value);
    tlv_send(pClientSession->netfd, &msg);
    printf("%s\n",value);
    return 0;
}